spec-sync: track V2 spec drift - #129
Conversation
There was a problem hiding this comment.
Pull request overview
Refreshes the tracked V2 OpenAPI snapshot and generated reference models. This is a mechanical-only spec-sync update; no client.v2 wiring is expected yet.
Changes:
- Adds build-schema sync/async contracts, metadata, and warnings.
- Updates the V2 endpoint inventory and removes obsolete schemas.
- Regenerates corresponding Pydantic reference models.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
specs/v2-aide.json |
Updates the normalized V2 OpenAPI snapshot. |
specs/_generated/v2_models.py |
Regenerates reference models from the snapshot. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (1)
src/landingai_ade/resources/v2/build_schema.py:51
- Because
stris aSequence[str], the public annotation permitsmarkdown_urls="https://x/y.md"; this conversion turns that URL into a list of characters and sends an invalid request. Normalize a bare string to a single URL (or reject it explicitly).
urls_list = list(cast(Sequence[str], markdown_urls))
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (2)
src/landingai_ade/resources/v2/build_schema.py:51
- Passing a single URL string is valid for this
Sequence[str]parameter, butlist(...)splits it into characters, so the API receives['h', 't', ...]instead of one URL. Normalize a string as one URL, as themarkdownsbranch does.
urls_list = list(cast(Sequence[str], markdown_urls))
src/landingai_ade/resources/v2/build_schema.py:233
- This 504 path also reuses timeout remediation that only mentions
parse_jobsandextract_jobs, so async-client users are not directed to the newbuild_schema_jobsresource. Pass endpoint-specific guidance through the shared helper here as well.
except APIStatusError as exc:
raise_if_sync_timeout(exc)
raise
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
src/landingai_ade/resources/v2/ground.py:128
- The async mirror also recommends
client.v2.ground_jobs, although the updated spec no longer contains/v2/ground/jobs. A 504 therefore points users at an unsupported route unless the spec removal is accidental; please reconcile the async remediation with the current contract.
raise_if_sync_timeout(exc, jobs_resource="ground_jobs")
… route raise_if_sync_timeout hardcoded a parse_jobs/extract_jobs message, so a 504 from build_schema (and ground) told users to use the wrong async resource. Add an optional keyword-only `jobs_resource` and render the message from it; pass the correct route at each call site (parse_jobs / extract_jobs / build_schema_jobs / ground_jobs). Kept optional (not required) so it's backward compatible with the released helper — surface-lock stays green — and when omitted it falls back to a generic "endpoint's async jobs route" rather than a wrong parse/extract one. Generalized the V2SyncTimeoutError docstring; the unit test asserts the message names the passed resource. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2d8293f to
1fd4633
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 18 out of 18 changed files in this pull request and generated 1 comment.
Comments suppressed due to low confidence (4)
src/landingai_ade/resources/v2/build_schema.py:64
- Empty
markdownsormarkdown_urlslists bypass this check even when no prompt or schema is supplied, so the method sends a request with no usable input despite its documented “at least one” requirement. Treat empty collections as absent here.
if md_list is None and urls_list is None and prompt_val is None and schema_val is None:
raise ValueError("build_schema requires at least one of `markdowns`, `markdown_urls`, `prompt`, or `schema`.")
src/landingai_ade/resources/v2/ground.py:99
- The synced spec removes both
/v2/ground/jobsoperations, so this new 504 remediation directs callers to a jobs endpoint that is no longer in the current contract. Keep the error non-specific or confirm/reintroduce the ground-jobs route before advertisingground_jobs.
raise_if_sync_timeout(exc, jobs_resource="ground_jobs")
src/landingai_ade/resources/v2/ground.py:128
- The synced spec removes both
/v2/ground/jobsoperations, so this new 504 remediation directs async-client callers to a jobs endpoint that is no longer in the current contract. Keep the error non-specific or confirm/reintroduce the ground-jobs route before advertisingground_jobs.
raise_if_sync_timeout(exc, jobs_resource="ground_jobs")
src/landingai_ade/lib/v2_errors.py:20
- This updated timeout documentation lists
ground_jobsas a matching async route, but the synced OpenAPI snapshot removes the ground-jobs collection and item paths. The documented remediation should not promise that route unless it remains an explicitly supported compatibility API.
The server cancels the work; use the endpoint's matching async jobs route
(`client.v2.parse_jobs` / `extract_jobs` / `build_schema_jobs` / `ground_jobs`),
then `.wait(...)`, for long-running inputs. The raised message names the route
for the specific endpoint that timed out."""
…dpoints)
BREAKING CHANGE: the V2 spec drift removed /v1/files, /v2/ground/jobs, and
/v2/ground/jobs/{job_id} server-side, so the SDK surface backed by them is
removed:
- client.v2.files (FilesResource / AsyncFilesResource, V2FileUploadResponse)
- client.v2.ground_jobs (GroundJobsResource / AsyncGroundJobsResource,
normalize_ground_job)
client.v2.ground (sync /v2/ground) stays. Since /v2/ground has no async route
and the spec declares no 504 for it, ground's 504→V2SyncTimeoutError handler is
dropped (a plain APIStatusError now surfaces). Tests and docs updated; requires a
major version bump. Labeled breaking-change-approved to bypass surface-lock.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
a406f5f to
618886f
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 24 changed files in this pull request and generated 4 comments.
Comments suppressed due to low confidence (1)
src/landingai_ade/types/v2/build_schema_response.py:46
openapi_specis the sole required field ofV2BuildSchemaMetadatain the updated spec, but this model exposes it as optional with aNonedefault. Make it required so the shipped response type accurately represents the new contract.
openapi_spec: Optional[str] = None
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 24 out of 24 changed files in this pull request and generated no new comments.
Comments suppressed due to low confidence (5)
src/landingai_ade/resources/v2/build_schema.py:51
markdown_urlsis annotated asSequence[str], so a caller can validly pass a single string. Converting that string withlist(...)sends one array entry per character instead of one URL. Mirror themarkdownsnormalization and wrap a string as a singleton list.
if is_given(markdown_urls) and markdown_urls is not None:
urls_list = list(cast(Sequence[str], markdown_urls))
api.md:67
ground_jobsis removed fromV2ResourceandGroundJobsResourceis deleted in this PR, so this public API overview now advertises an attribute that raisesAttributeError. Remove it from the unified-job resource list.
`client.v2.parse_jobs`, `client.v2.extract_jobs`, `client.v2.build_schema_jobs`, and `client.v2.ground_jobs` all return a single, unified <a href="./src/landingai_ade/types/v2/job.py">`Job`</a> shape, even though the underlying parse/extract/build-schema/ground job envelopes differ upstream -- `Job.raw` retains the full original envelope as an escape hatch for any field not surfaced on the typed model.
api.md:162
- This pagination note still lists the removed
ground_jobsresource. Keeping it here directs users to a nonexistent API.
- `parse_jobs.list` / `extract_jobs.list` / `build_schema_jobs.list` / `ground_jobs.list` all return a `JobList` (a `list[Job]` subclass) carrying pagination metadata: `.has_more`, `.org_id`, `.page`, `.page_size`.
docs/v2-testing.md:12
normalize_ground_jobis deleted from_normalize.pyin this PR, so the testing matrix should not claim that this nonexistent normalizer is covered.
| Job normalization | `tests/test_v2_normalize.py` | `normalize_parse_job` / `normalize_extract_job` / `normalize_build_schema_job` / `normalize_ground_job`: envelope → unified `Job` (status, timestamps, `result`, `error`). |
docs/v2-testing.md:115
- This section still documents
normalize_ground_job, but that function and the ground jobs surface are removed by the PR. Remove it so the documented normalization surface matches the shipped code.
`normalize_parse_job`, `normalize_extract_job`, `normalize_build_schema_job`, and
`normalize_ground_job` fold the upstream job envelopes into the unified `Job`. All
are tolerant of field-name drift:
- build_schema: reject empty containers / blank prompt (markdowns=[], prompt="") in the "at least one input" guard instead of sending a no-op request; treat a bare markdown_urls string as one URL rather than splitting it into single-character URLs (mirrors the markdowns fix). - build_schema_response: make warning code/msg and metadata openapi_spec required non-null, matching the spec / _generated reference. - docs: drop the removed client.v2.files, V2FileUploadResponse, ground_jobs, and normalize_ground_job from api.md and docs/v2-testing.md (missed in the removal); ground is documented as sync-only. - tests: cover the empty-input guard and the bare markdown_urls string. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Automated V2 spec-sync PR (
client.v2).Gates (surface-lock, V2 contract tests, lint/test/typecheck) must pass. When present, the AI commit is a draft a human finishes (the V2 ergonomic layer — unified Job, dual-host, schema coercion — is not in the spec). Human review required before merge.
What changed
AI-generated from the PR diff — verify against the actual changes.
Public
client.v2surface tracked from the V2 spec drift:Added — build-schema
client.v2.build_schema(*, markdowns=…, markdown_urls=…, prompt=…, schema=…) -> V2BuildSchemaResponse(POST /v2/extract/build-schema). Synchronous schema generation; sent asmultipart/form-datawhen anymarkdownsentry is a file, JSON otherwise;schemaaccepts a pydantic model /dict/ JSON string.client.v2.build_schema_jobs.{create,get,list,wait}(POST/GET /v2/extract/build-schema/jobs[/{job_id}]) — async variant;createalso takesservice_tier.V2BuildSchemaResponse(extraction_schema,metadata),V2BuildSchemaMetadata,V2BuildSchemaWarning,V2BuildSchemaBilling.Removed (breaking — routes retired upstream)
client.v2.files.upload(*, file) -> str(POST /v1/files) andV2FileUploadResponse.client.v2.ground_jobs.{create,get,list,wait}(/v2/ground/jobs[/{job_id}]), plusV2GroundJobCreateParamsandnormalize_ground_job.Kept / changed
client.v2.ground(*, extraction_metadata, structure) -> V2GroundResultstays (POST /v2/ground), now sync-only (no async route); its504 → V2SyncTimeoutErrorhandler is dropped since the spec declares no 504 for it.raise_if_sync_timeoutgains a keyword-onlyjobs_resourceso a 504's remediation names the endpoint's own async route (parse / extract / build_schema) instead of a hardcoded parse/extract one.build_schemarejects empty containers / blank prompt in the "at least one input" guard and treats a baremarkdown_urlsstring as a single URL;V2BuildSchemaResponsewarningcode/msgand metadataopenapi_specare required non-null (matches spec).